package com.example.foo.admin.web.member;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtils;
import com.shitu.api.response.OrderPayResponse;
import com.shitu.api.response.QueryAcctInfoResponse;
import com.shitu.api.response.OrderPayResponse.PayOrderDetail;
import com.example.support.wanquanpay.WanquanPay;
import com.example.support.wanquanpay.WanquanPayException;
import com.example.core.PageResult;
import com.example.core.Pageable;
import com.example.foo.ftt.model.FttUser;
import com.example.foo.ftt.service.FttUserService;
import com.example.foo.member.model.MemberIdcard;
import com.example.foo.member.model.Withdraw;
import com.example.foo.member.query.WithdrawQuery;
import com.example.foo.member.service.MemberIdcardService;
import com.example.foo.member.service.WithdrawFacadeService;
import com.example.foo.member.service.WithdrawService;
import com.example.support.redis.RedisHelper;

@org.springframework.web.bind.annotation.RestController
public class WithdrawAction {

	protected final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(getClass());

	private final MemberIdcardService memberIdcardService;
	private final FttUserService fttUserService;
	private final WithdrawService withdrawService;
	private final WithdrawFacadeService withdrawFacadeService;
	private final WanquanPay wanquanPay;

	public WithdrawAction(MemberIdcardService memberIdcardService,
			FttUserService fttUserService,
			WithdrawService withdrawService,
			WithdrawFacadeService withdrawFacadeService,
			WanquanPay wanquanPay) {
		this.memberIdcardService = memberIdcardService;
		this.fttUserService = fttUserService;
		this.withdrawService = withdrawService;
		this.withdrawFacadeService = withdrawFacadeService;
		this.wanquanPay = wanquanPay;
	}

	@GetMapping("/api/withdraws")
	public AjaxResult index(WithdrawQuery withdrawQuery, Pageable pageable) {
		PageResult<Withdraw> pageResult = withdrawService.findWithdraws(withdrawQuery, pageable);

		List<Long> userIds = pageResult.getRows()
				.stream()
				.map(Withdraw::getUserId)
				.collect(Collectors.toList());
		Map<Long, FttUser> userIdFttUserMap = fttUserService.findFttUsersByUserIdsAsMap(userIds);

		List<WithdrawVO> withdrawVOs = pageResult.getRows()
				.stream()
				.map(withdraw -> new WithdrawVO(withdraw, userIdFttUserMap.get(withdraw.getUserId())))
				.collect(Collectors.toList());
		return AjaxResult.successData(new PageResult<>(withdrawVOs, pageResult.getTotal()));
	}

	@GetMapping("/api/withdraws/export")
	public AjaxResult export(WithdrawQuery withdrawQuery) {
		Pageable pageable = new Pageable(1, 65535);
		PageResult<Withdraw> pageResult = withdrawService.findWithdraws(withdrawQuery, pageable);

		List<Long> userIds = pageResult.getRows()
				.stream()
				.map(Withdraw::getUserId)
				.collect(Collectors.toList());
		Map<Long, FttUser> userIdFttUserMap = fttUserService.findFttUsersByUserIdsAsMap(userIds);

		List<WithdrawVO> withdrawVOs = pageResult.getRows()
				.stream()
				.map(withdraw -> new WithdrawVO(withdraw, userIdFttUserMap.get(withdraw.getUserId())))
				.collect(Collectors.toList());

		Map<String, String> fields = new LinkedHashMap<>();
		fields.put("ID", "id");
		fields.put("创建时间", "createdAt");
		fields.put("状态", "state");
		fields.put("提现单号", "withdrawNo");
		fields.put("银行名称", "bankName");
		fields.put("持卡人", "cardHolder");
		fields.put("卡号", "cardNumber");
		fields.put("提现金额", "money");
		fields.put("手续费", "serviceFee");
		fields.put("到账金额", "actualMoney");
		fields.put("备注", "memo");
		fields.put("外部订单号", "outerOrderNo");
		fields.put("userId", "userId");
		fields.put("角色", "roleLevel");
		fields.put("角色T", "roleLevelText");
		fields.put("网体级别", "fttLevel");
		fields.put("网体级别T", "fttLevelText");
		fields.put("手机号", "cellphone");
		fields.put("姓名", "idname");
		return new ExcelUtils<>(WithdrawVO.class).export(fields, withdrawVOs);
	}

	@GetMapping("/api/withdraws/{id}")
	public AjaxResult showWithdraw(@PathVariable("id") Long id) {
		Withdraw withdraw = withdrawService.findWithdrawById(id);
		if (withdraw == null) {
			return AjaxResult.error(404, "Not Found");
		}

		FttUser fttUser = fttUserService.findFttUserByUserId(withdraw.getUserId());

		return AjaxResult.successData(new WithdrawVO(withdraw, fttUser));
	}

	@PutMapping("/api/withdraws/stateBatch")
	public AjaxResult updateWithdrawsState(@RequestParam("ids") List<Long> ids, Withdraw withdrawForm) {
		//
		Withdraw.State destState = withdrawForm.getState();
		String memo = withdrawForm.getMemo();

		//
		if (ids == null || ids.isEmpty()) {
			return AjaxResult.error(400, "ids must not be null");
		}
		if (destState == null) {
			return AjaxResult.error(400, "state must not be null");
		}

		//
		List<Withdraw> withdraws = withdrawService.findWithdrawsByIds(ids);

		//
		if (destState == Withdraw.State.success) {
			QueryAcctInfoResponse queryAcctInfoResponse = wanquanPay.queryMerchant();
			BigDecimal availableFee = new BigDecimal(queryAcctInfoResponse.getAvailableFee());
			BigDecimal destTotalMoney = withdraws.stream()
					.map(Withdraw::getMoney)
					.reduce(BigDecimal.ZERO, BigDecimal::add);
			if (availableFee.compareTo(destTotalMoney) < 0) {
				return AjaxResult.error(400, String.format("商户众邦账户可用余额不足！可用%s, 预期%s", availableFee, destTotalMoney));
			}
		}

		//
		for (Withdraw withdraw : withdraws) {
			if (withdraw.getState() != Withdraw.State.pending) {
				return AjaxResult.error(400, String.format("Withdraw#%s, 重复审批！", withdraw.getId()));
			}

			String lockKey = String.format("lock:withdraw:id_%s", withdraw.getId());
			if (!RedisHelper.setnxex(lockKey, Duration.ofMinutes(10).getSeconds(), "-")) {
				return AjaxResult.error(400, String.format("Withdraw#%s, 已锁定！", withdraw.getId()));
			}

			if (destState == Withdraw.State.success) {
				withdrawFacadeService.updateWithdrawSuccess(withdraw.getId(), memo);

				BigDecimal actualMoney = withdraw.getMoney().subtract( withdraw.getServiceFee() );
				MemberIdcard memberIdcard = memberIdcardService.findMemberIdcardByUserId(withdraw.getUserId());

				String memberId = memberIdcard.getOuterMemberId();
				String idCard = memberIdcard.getIdcard();
				String name = memberIdcard.getIdname();
				String fee = actualMoney.toString();
				try {
					OrderPayResponse orderPayResponse = wanquanPay.orderPayBank(memberId, idCard, name, fee);
					if (orderPayResponse.getStatusCode().equals("1001")) {
						PayOrderDetail payOrderDetail = orderPayResponse.getPayList().get(0);
						String memo_p = (memo == null ? "" : memo + " ") + orderPayResponse.getMsg();
						String outerOrderNo = payOrderDetail.getOrderNo();
						withdrawService.updateWithdrawOuterOrderNo(withdraw.getId(), memo_p, outerOrderNo);
					} else {
						throw new IllegalStateException();
					}
				} catch (WanquanPayException e) {
					return AjaxResult.error(500, e.getMessage());
				}

			} else if (destState == Withdraw.State.failure) {
				withdrawFacadeService.updateWithdrawFailure(withdraw.getId(), memo);
			} else {
				throw new IllegalStateException();
			}
		}

		return AjaxResult.success();
	}

}
